﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using H2.Streams;
using H2.DataTypes;

namespace Mystery.Unicode
{
    public class UnicodeReference
    {
        public string StringIDReference;
        public UnicodeTag TagReference;

        List<UnicodeReference> Siblings = new List<UnicodeReference>();

        public string StringData;

        public static List<UnicodeReference> Create(string[] strings, UnicodeIndex[] indices, UnicodeTag[] tags)
        {
            List<UnicodeReference> references = new List<UnicodeReference>(strings.Length);
            int offset = 0;
            int siblingsRemaining = 0;
            for (int i = 0; i < strings.Length; i++)
            {
                UnicodeReference ur = new UnicodeReference();

                ur.StringData = strings[i];

                UnicodeIndex ui = Array.Find(indices, (UnicodeIndex x) => { return x.StringOffset == offset; });
                ur.StringIDReference = (ui == null) ? "" : ui.ReferenceID.ToString();

                UnicodeTag ut = Array.Find(tags, (UnicodeTag x) => { return (x != null && x.EnglishStringIndex == i); });
                ur.TagReference = ut;



                if (siblingsRemaining > 0)
                {
                    references[references.Count - 1].Siblings.Add(ur);
                    siblingsRemaining--;
                }
                else
                {
                    if (ut != null) siblingsRemaining = ut.EnglishStringCount - 1;
                    references.Add(ur);
                }

                offset += strings[i].Length + 1;
            }

            return references;
        }

        public static int WriteStringTable(MapStream map, List<UnicodeReference> references)
        {
            int size = 0;
            for (int i = 0; i < references.Count; i++)
            {
                map.Write(references[i].StringData);
                map.Write((byte)0);

                size += references[i].StringData.Length + 1;
                size += WriteStringTable(map, references[i].Siblings);
            }
            return size;
        }

        public static int WriteIndexTable(MapStream map, List<UnicodeReference> references, int currentOffset)
        {
            int count = 0;
            for (int i = 0; i < references.Count; i++)
            {
                UnicodeReference ur = references[i];

                StringID sidRef = map.StringIDs[0];
                try { sidRef = map.StringIDs[map.StringIDs.IndexOf(ur.StringIDReference)]; }
                catch { }

                map.Write(sidRef);
                map.Write(currentOffset);

                currentOffset += ur.StringData.Length + 1;

                count++;
                count += WriteIndexTable(map, ur.Siblings, currentOffset);
            }

            return count;
        }

        public static void WriteTagData(MapStream map, List<UnicodeReference> references)
        {
            for (int i = 0; i < references.Count; i++)
            {
                UnicodeReference ur = references[i];
                if (ur.TagReference == null) continue;

                ur.TagReference.EnglishStringIndex = (ushort)i;
                ur.TagReference.EnglishStringCount = (ushort)ur.Siblings.Count;

                if (ur.TagReference != null)
                {
                    map.Position = ur.TagReference.Offset;
                    UnicodeTag.Write(map, ur.TagReference);
                }
            }
        }

        public static List<UnicodeReference> Combine(List<UnicodeReference> references, List<UnicodeReference> otherReferences)
        {
            List<UnicodeReference> result = new List<UnicodeReference>(references);

            foreach (UnicodeReference otherReference in otherReferences)
            {
                //Possible Error, doesnt check children...
                //int index = result.FindIndex((UnicodeReference ur) => { return ur.StringIDReference.Equals(otherReference.StringIDReference); });
                result.RemoveAll((UnicodeReference ur) => { return ur.StringIDReference.Equals(otherReference.StringIDReference); });
                //if (index >= 0)
                //{
                //    result.RemoveAt(index);
                //}
            }

            result.AddRange(otherReferences);

            return result;
        }

        public override string ToString()
        {
            return StringData;
        }
    }
}
